#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
#endregion

namespace KLib.Screens
{
    #region Enums
    public enum ScreenState
    {
        Hidden = 0,
        TransitionOn = 1,
        TransitionOff = -1
    }

    #endregion

    public abstract class GameScreen
    {

        #region Fields
        private bool isExiting = false;
        private bool isPopup = false;
        private bool otherScreenHasFocus;

        private ScreenState screenState;
        private ScreenManager manager;

        private TimeSpan transitionTime = TimeSpan.Zero;
        private TimeSpan elapsedTransitionTime = TimeSpan.Zero;

        private float transitionPercentage = 0f;
        private bool requiresUpdate = true;
        private bool requiresDraw = true;
        #endregion

        #region Properties
        /// <summary>
        /// Gets if the screen is actually exiting permanently. This is NOT flagged if the screen is just not visible,
        /// Once the transition time is complete, the GameScreen will remove itself.
        /// </summary>
        public bool IsExiting
        {
            get { return isExiting; }
            protected internal set { isExiting = value; }
        }

        /// <summary>
        /// Gets if this screen is a Popup. If it is, then it does not compleatly cover other screens, it just appears above them
        /// and the other screens are still drawn
        /// </summary>
        public bool IsPopup
        {
            get { return isPopup; }
            protected set { isPopup = value; }
        }


        /// <summary>
        /// Gets if this screen is active, and will take input from the user
        /// </summary>
        public bool IsActive
        {
            get 
            {
                return (!otherScreenHasFocus &&
                    screenState == ScreenState.TransitionOn)
                    || requiresDraw;
            }
        }

        /// <summary>
        /// Returns the current state of the screen (What its current mode is)
        /// </summary>
        public ScreenState ScreenState
        {
            get { return screenState; }
            protected set { screenState = value; }
        }

        /// <summary>
        /// Gets the ScreenManager that is in charge of this screen. Provides access to higher level assets like
        /// a SpriteBatch, and ContentManager
        /// </summary>
        public ScreenManager ScreenManager
        {
            get { return manager; }
            internal set { manager = value; }
        }

        /// <summary>
        /// Returns how long it takes for the screen to go from compleatly Hidden to Compleatly Visible
        /// </summary>
        public TimeSpan TransitionTime
        {
            get { return transitionTime; }
            protected set { transitionTime = value; }
        }

        /// <summary>
        /// Returns how long it takes for the screen to go from compleatly Visible to Compleatly Hidden.
        /// </summary>
        public TimeSpan ElapsedTransitionTime
        {
            get { return elapsedTransitionTime; }
            protected set { elapsedTransitionTime = value; }
        }

        /// <summary>
        /// Returns the percentage of how far into the transition this screen is (0 = compleated, 1 = starting)
        /// </summary>
        public float TransitionPercentage
        {
            get { return transitionPercentage; }
        }

        /// <summary>
        /// Returns the current alpha (Transparency) of this screen (255 = fully visible, 0 = fully transparent)
        /// </summary>
        public byte TransitionAlpha
        {
            get { return (byte)(transitionPercentage * 255); }
        }

        protected Microsoft.Xna.Framework.Graphics.Color ScreenColor
        {
            get { return new Microsoft.Xna.Framework.Graphics.Color(255, 255, 255, TransitionAlpha); }
        }

        /// <summary>
        /// Gets if this screen should be update this frame
        /// </summary>
        public bool RequiresUpdate
        {
            get { return requiresUpdate; }
            protected set { requiresUpdate = value; }
        }

        /// <summary>
        /// Gets if this screen should be drawn
        /// </summary>
        public bool RequiresDraw
        {
            get { return requiresDraw; }
            protected set { requiresDraw = value; }
        }
        #endregion

        #region Initialization
        public virtual void Initialize()
        {
        }
        public virtual void LoadContent()
        {
            Reflection.Reflect(ScreenManager.Game, this);
        }
        #endregion

        #region Methods

        public virtual void Update(GameTime gameTime)
        {
            /*if ((TransitionAlpha < 255
                || screenState == ScreenState.TransitionOff)
                && ScreenManager.Input != null)
                ScreenManager.Input.Reset();*/

            if (screenState == ScreenState.Hidden
                || (screenState == ScreenState.TransitionOff && transitionPercentage == 0))
            {
                screenState = ScreenState.Hidden;
                requiresUpdate = false;
                requiresDraw = false;
            }

            if (screenState == ScreenState.TransitionOn && transitionPercentage == 1)
                return;

            float transitionDelta;

            elapsedTransitionTime -= gameTime.ElapsedGameTime;

            //Set the ammount to transition this frame
            if (elapsedTransitionTime <= TimeSpan.Zero)
                transitionDelta = 1;
            else
                transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / elapsedTransitionTime.TotalMilliseconds);

            //Apply the transition
            transitionPercentage += transitionDelta * (int)screenState;
            transitionPercentage = MathHelper.Clamp(transitionPercentage, 0, 1);
        }

        public virtual void Draw(GameTime gameTime)
        {
        }

        public virtual void MakeActive()
        {
            this.ScreenState = ScreenState.TransitionOn;
            this.requiresDraw = true;
            this.requiresUpdate = true;
            this.elapsedTransitionTime = transitionTime;
        }

        public virtual void MakeInactive(bool waitForTransition)
        {
            this.ScreenState = ScreenState.TransitionOff;
            this.requiresDraw = waitForTransition;
            this.requiresUpdate = waitForTransition;
        }
        #endregion

        #region Helper Methods
        
        #endregion
    }
}
